package com.boot.notes.stream;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * JDK8新特性之 Stream API
 *
 * @author mkq
 */
public class StreamApiUtils {


    public static List<StudentEntity> initList() {
        List<StudentEntity> list = new ArrayList<>();
        list.add(new StudentEntity(1, "刘德华", 53, "1"));
        list.add(new StudentEntity(2, "刘青云", 56, "1"));
        list.add(new StudentEntity(3, "张曼玉", 53, "0"));
        list.add(new StudentEntity(4, "刘亦菲", 32, "0"));
        list.add(new StudentEntity(5, "梁家辉", 68, "1"));
        list.add(new StudentEntity(6, "傅诗淇", 33, "1"));
        list.add(new StudentEntity(7, "关晓彤", 25, "0"));
        list.add(new StudentEntity(8, "邓伦", 28, "1"));
        list.add(new StudentEntity(9, "肖若腾", 24, "1"));
        list.add(new StudentEntity(10, "全红婵", 14, "0"));
        list.add(new StudentEntity(1, "刘德华", 53, "1"));
        list.add(new StudentEntity(11, "刘德华", 53, "1"));
        return list;
    }

    /**
     * 自定义数据模型
     *
     * @param student
     * @return
     */
    public static Map<String, Object> getStudent(StudentEntity student) {
        Map<String, Object> map = new HashMap<>();
        map.put("name", student.getName());
        return map;
    }

    public static Integer getStudentNum(StudentEntity student) {
//        Integer i = 0;
//        i++;
        return 1;
    }

    /**
     * 初始化一个流的方式
     *
     * @Date 2021-08-28
     */
    public static void initStream() {

        // todo 1.静态工厂方法
        //of of(T... values)：返回含有多个T元素的Stream  of(T t)：返回含有一个T元素的Stream
        Stream stream = Stream.of("a", "b", "c");
        Stream<Integer> integerStream = Stream.of(1, 2, 3);

        // generate generate(Supplier<T> s)：返回一个无限长度的Stream
        Stream<Double> generateB = Stream.generate(() -> java.lang.Math.random());
        Stream<Double> generateC = Stream.generate(java.lang.Math::random);

        // iterate  iterate(T seed, UnaryOperator<T> f)
        Stream.iterate(1, item -> item + 1).limit(10).forEach(System.out::println);

        // empty empty方法返回一个空的顺序Stream，该Stream里面不包含元素项。
        Stream.empty();


        // todo 2.Collection接口和数组的默认方法 在Collection接口中，定义了一个默认方法stream()，用来生成一个Stream。
        // 从数组创建
        String[] strArray = new String[]{"a", "b", "c"};
        stream = Arrays.stream(strArray);

        // 从集合创建
        List<String> list = Arrays.asList(strArray);
        stream = list.stream(); // 串行流
        stream = list.parallelStream(); //并行流


        // todo 其他栗子
        // 使用random创建一个无限流
        Random random = new Random();
        random.ints().limit(10).forEach(System.out::println);
        // 自己产生流
        Stream.generate(() -> random.nextInt()).limit(20).forEach(System.out::println);
        // 数字流
        IntStream.of(new int[]{1, 2, 3}).forEach(System.out::println);
        IntStream.range(1, 3).forEach(System.out::println);
        IntStream.rangeClosed(1, 3).forEach(System.out::println);


    }

    public static void main(String[] args) {
        List<StudentEntity> list = initList();

        // todo 获取所有的姓名 .map()
        List<String> nameList = list.stream().map(s -> s.getName()).collect(Collectors.toList());
        System.out.println("====================================== 所有姓名集合：------" + nameList + "====================================");
        list.stream().map(s -> s.getName()).collect(Collectors.toList()).forEach(System.out::println);

        // todo 获取list中的女性数据 运用的的是过滤 .filter()函数
        List<StudentEntity> sex_0 = list.stream().filter(s -> s.getSex().equals("0")).collect(Collectors.toList());
        System.out.println("====================================== 集合中的女性数据 sex_0：------" + sex_0.toString() + "====================================");

        // todo 获取女性的条数 .count()
        Long count = list.stream().filter(s -> s.getSex().equals("0")).count();
        System.out.println("====================================== 集合中的女性共 count：------" + count + " 条====================================");


        // todo 获取前两个女性数据 .limit()函数
        List<StudentEntity> sex_0_limit = list.stream().filter(s -> s.getSex().equals("0")).limit(2).collect(Collectors.toList());
        System.out.println("====================================== 获取前两条女性数据 sex_0_limit ：------" + sex_0_limit + " ====================================");
        list.stream().filter(s -> s.getSex().equals("0")).limit(2).collect(Collectors.toList()).forEach(System.out::println);


        // todo 去重 .distinct()
        List<StudentEntity> liudehua = list.stream().distinct().collect(Collectors.toList());
        System.out.println("====================================== 去重前集合数量：------" +
                list.size() + " \n 去重后集合数量：" + liudehua.size() + " ---" +
                liudehua + "====================================");

        // todo 按照年龄排序 .sorted() 从小到大
        list.stream().sorted((s1, s2) -> s1.getAge() - s2.getAge()).collect(Collectors.toList()).forEach(System.out::println);

        // todo 双条件排序：按照年龄正序、ID倒叙
        list.stream().sorted(Comparator.comparing(StudentEntity::getAge).thenComparing(StudentEntity::getId).reversed()).collect(Collectors.toList());


        // todo 从第二个女性开始获取 skip(0)从0开始的 获取所有女性
        List<StudentEntity> sex_0_skip = list.stream().filter(s -> s.getSex().equals("0")).skip(1).collect(Collectors.toList());
        System.out.println("====================================== 获取前两条女性数据 sex_0_skip ：------" + sex_0_skip + " ====================================");
        list.stream().filter(s -> s.getSex().equals("0")).skip(1).collect(Collectors.toList()).forEach(System.out::println);

        // todo 总条数 .count()
        count = list.stream().count();
        System.out.println("====================================== 总共条数：------" + count + " ====================================");


        // todo 判断是否全是男性 .allMatch()
        boolean boo = list.stream().allMatch(s -> "1".equals(s.getSex()));
        System.out.println("====================================== 是否全是男性：------" + boo + " ====================================");

        // todo 判断是否有未成年 .anyMatch()
        boolean boo_ = list.stream().anyMatch(s -> s.getAge() > 18);
        System.out.println("====================================== 是否有未成年：------" + boo_ + " ====================================");

        // todo 判断是否全是男性 .noneMatch()
        boolean boo_all = list.stream().noneMatch(s -> "1".equals(s.getSex()));
        System.out.println("====================================== 是否全是男性：------" + boo_all + " ====================================");

        // todo 按照性别分类 单一条件分组
        Map<String, List<StudentEntity>> map = list.stream().collect(
                Collectors.groupingBy(
                        StudentEntity::getSex
                ));

        System.out.println("====================================== 性别分类：------" + map.toString() + " ====================================");
        // 返回自定义数据结构
//        mapping函数：mapper：返回参数对象，downstream收集的集合值。
//        Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper,
//                Collector<? super U, A, R> downstream)

        List<Map<String, Object>> lm = list.stream().collect(Collectors.mapping(s -> getStudent(s), Collectors.toList()));
        System.out.println("*********************************************** 自定义 " + lm + "************************************");

        Map<String, List<Map<String, Object>>> myMap = list.stream().collect(
                Collectors.groupingBy(
                        StudentEntity::getSex, Collectors.mapping(s -> getStudent(s), Collectors.toList())
                ));
        System.out.println("====================================== 性别分类 - 自定义返回结果集 map：------" + myMap.toString() + " ====================================");

        // todo 按照性别分类 返回各组数量
        Map<String, Long> myMapNum = list.stream().collect(
                Collectors.groupingBy(
                        StudentEntity::getSex, Collectors.mapping(s -> 1, Collectors.counting())
                ));
        System.out.println("====================================== 性别分类 - 返回各组条数：------" + myMapNum + " ====================================");

        Map<String, List<String>> myMap_ = list.stream().collect(
                Collectors.groupingBy(
                        StudentEntity::getSex, Collectors.mapping(s -> s.getName(), Collectors.toList())
                ));
        System.out.println("====================================== 性别分类 - 自定义返回结果集 string：------" + myMap_.toString() + " ====================================");

        Map<String, Map<String, Object>> mmm = list.stream().collect(
                Collectors.groupingBy(
                        StudentEntity::getSex, Collectors.collectingAndThen(Collectors.toList(), s -> {
                            Map<String, Object> mm = new HashMap<>();
                            mm.put("count", s.stream().count());
                            //对分组的list求和
                            mm.put("ageSum", s.stream().mapToDouble(StudentEntity::getAge).sum());
                            return mm;
                        })
                ));
        System.out.println("====================================== 性别分组 自定义返回结果集：------" + mmm + " ====================================");

        Map<String, Object> mmm_ = list.stream().collect(
                Collectors.groupingBy(
                        StudentEntity::getSex, Collectors.collectingAndThen(Collectors.toList(), s -> {

                            return s.stream().mapToDouble(StudentEntity::getAge).sum();
//                            return  s.size();
                        })
                ));

        System.out.println("====================================== 性别分组 自定义返回结果集：------" + mmm_ + " ====================================");

        // todo 多条件分组
        Map<String, Map<Integer, List<StudentEntity>>> mmap = list.stream().collect(
                Collectors.groupingBy(
                        StudentEntity::getSex, Collectors.groupingBy(StudentEntity::getAge)
                ));
        System.out.println("====================================== 多条件分组 性别&年龄：------" + mmap.toString() + " ====================================");

        Map<String, Map<String, List<StudentEntity>>> mmap_ = list.stream().collect(
                Collectors.groupingBy(
                        StudentEntity::getSex, Collectors.groupingBy(s -> s.getName().substring(0, 1))
                ));
        System.out.println("====================================== 多条件分组 性别&姓氏：------" + mmap_.toString() + " ====================================");

        // todo 按照性别分组，获取每个性别年龄合
        Map<String, Integer> mapCount = list.stream().collect(
                Collectors.groupingBy(
                        StudentEntity::getSex, Collectors.summingInt(StudentEntity::getAge)
                ));
        System.out.println("====================================== 性别分组 年龄合：------" + mapCount + " ====================================");

        // 平均年龄
        Map<String, Double> mapAverag = list.stream().collect(
                Collectors.groupingBy(
                        StudentEntity::getSex, Collectors.averagingInt(StudentEntity::getAge)
                ));
        System.out.println("====================================== 性别分组 每组平均年龄：------" + mapAverag + " ====================================");

        // 每组年龄最大的 maxBy 最小的 mixBy 或者maxBy().reversed() 取反
        Map<String, Optional<StudentEntity>> mapMax = list.stream().collect(
                Collectors.groupingBy(
                        StudentEntity::getSex, Collectors.maxBy(Comparator.comparing(StudentEntity::getAge))
                ));
        System.out.println("====================================== 性别分组 每组年龄最大的：------" + mapMax + " ====================================");

        // 每组年龄最小的
        Map<String, Optional<StudentEntity>> mapMinAge = list.stream().collect(
                Collectors.groupingBy(
                        StudentEntity::getSex, Collectors.maxBy(Comparator.comparingInt(StudentEntity::getAge).reversed())
                ));

        System.out.println("====================================== 性别分组 每组平均年龄最小值：------" + mapMinAge + " ====================================");

        // todo 获取重复数据
        // 重复的名字
        List<String> name = list.stream().collect(
                Collectors.groupingBy(s ->
                        s.getName(), Collectors.counting()
                )).entrySet().stream().filter(m -> m.getValue() > 1).map(Map.Entry::getKey).collect(Collectors.toList());

        System.out.println("====================================== 重复数据 name：------" + name);

        // 重复的名字 对应的次数
        List<Map.Entry<String, Long>> nameCount = list.stream().collect(
                Collectors.groupingBy(s ->
                        s.getName(), Collectors.counting()
                )).entrySet().stream().filter(m -> m.getValue() > 1).collect(Collectors.toList());

        System.out.println("====================================== 重复数据 name=次数：------" + nameCount);

        // 重复的名字
        List<StudentEntity> entity = list.stream().collect(
                Collectors.groupingBy(s ->
                        s, Collectors.counting()
                )).entrySet().stream().filter(m -> m.getValue() > 1).map(Map.Entry::getKey).collect(Collectors.toList());

        System.out.println("====================================== 重复数据 entity：------" + entity);

    }

}
